/* ------------------------------------------------------------------------*
 *
 * ------------------------------------------------------------------------*/
#include "sst25_cmd.h"
#include "spi.h"
#include "pincfg.h"
     
uint8_t scs;

#define SST25Cs(x)    x?(PGout(10)=1):(PGout(10)=0)
#define SpiRw(x)     SPI3_ReadWriteByte(x)
#define SpiDmaRw(x,y,z)




void SST25Wait(uint8_t Cnt)
{
    while(Cnt --){};
}

/*****************************************************************************//*!
* @brief   read status.
*               The Status Register may be read at any time, 
*               even while a Program, Erase or Write Status Register cycle is in progress. 
* @param   none
*
* @return  statues
*
* @ Pass/ Fail criteria: none
*****************************************************************************/ 
uint8_t SST25CmdStRead(void)
{
    uint8_t St;
    
    SST25Cs(0); 
    SpiRw( SST25CMD_Read_Status);
    St = SpiRw( 0xFF);
    SST25Cs(1); 
    
    return St;
}

void SST25CmdStWrite(uint8_t St){

    while(SST25Busy()){}
    
    while( SST25Q_ST_WRITE_EN != (SST25CmdStRead()&SST25Q_ST_WRITE_EN))
    SST25CmdWriteEn();
    
    SST25Cs(0); 
    SpiRw( SST25CMD_Write_Status);
    St = SpiRw( St);
    SST25Cs(1); 
    
    NOP20();
    while(SST25Busy()){}
    
    while( SST25Q_ST_WRITE_EN == (SST25CmdStRead()&SST25Q_ST_WRITE_EN))
    SST25CmdWriteDis();

}

/*****************************************************************************//*!
* @brief   read busy statues.
*               The Status Register may be read at any time, 
*               even while a Program, Erase or Write Status Register cycle is in progress. 
* @param   none
*
* @return  busy or not
*
* @ Pass/ Fail criteria: none
*****************************************************************************/ 
uint8_t  SST25Busy(void)
{
    uint8_t FlashSt;
    
    SST25Cs(0); 
    SpiRw( SST25CMD_Read_Status);
    FlashSt = SpiRw( 0xFF);
    SST25Cs(1); 
    
    return ((uint8_t)(FlashSt & SST25Q_ST_BUSY_MASK));
}

/*****************************************************************************//*!
* @brief   write enable.
*               
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/ 
void SST25CmdWriteEn(void)
{
    SST25Cs(0); 

    SpiRw( SST25CMD_Write_Enable);
   
    SST25Cs(1); 
}

/*****************************************************************************//*!
* @brief   write disable.
*               
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/ 
void SST25CmdWriteDis(void)
{
    SST25Cs(0); 

    SpiRw( SST25CMD_Write_Disable);
   
    SST25Cs(1); 
}

/*****************************************************************************//*!
* @brief   Erase aector.       4k
*               
* @param   addr:      data address in chip
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/ 
void SST25SectorErase(uint32_t addr)
{
    UINT32_VAL Par;
    
    //waiting for idle
    while(SST25Busy()){}
    
    while( SST25Q_ST_WRITE_EN != (SST25CmdStRead()&SST25Q_ST_WRITE_EN))
    SST25CmdWriteEn();
        
    SST25Cs(0);
    Par.Val = addr;   
    SpiRw( SST25CMD_Sector_Erase);
    SpiRw( Par.byte.UB);
    SpiRw( Par.byte.HB);
    SpiRw( Par.byte.LB); 
    SST25Cs(1);
    
    NOP20();
    while(SST25Busy()){}  
}

/*****************************************************************************//*!
* @brief   Erase block.      32k
*               
* @param   addr:      data address in chip
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
void SST25BlockErase(uint32_t addr)
{
    UINT32_VAL Par;
    
    //waiting for idle
    while(SST25Busy()){}
    while( SST25Q_ST_WRITE_EN != (SST25CmdStRead()&SST25Q_ST_WRITE_EN))
    SST25CmdWriteEn();
        
    SST25Cs(0);
    Par.Val = addr;   
    SpiRw( SST25CMD_Block_Erase_32K);
    SpiRw( Par.byte.UB);
    SpiRw( Par.byte.HB);
    SpiRw( Par.byte.LB); 
    SST25Cs(1);
    
    NOP20();
    while(SST25Busy()){}
}

/*****************************************************************************//*!
* @brief   Erase chip.
*               
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/
void SST25ChipErase(void )
{
    while(SST25Busy()){}
    while( SST25Q_ST_WRITE_EN != (SST25CmdStRead()&SST25Q_ST_WRITE_EN))
    SST25CmdWriteEn();
        
    SST25Cs(0);  
    SpiRw( SST25CMD_Chip_Erase);
    SST25Cs(1);   
    
    NOP20();
    while(SST25Busy()){}
    
}

/*****************************************************************************//*!
* @brief   read data.
*               
* @param   addr          address in chip
*          len           length will be read
*          des           destination
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/ 
void SST25Read(uint32_t addr,uint32_t Len,uint8_t *Des)
{
    UINT32_VAL Par;
    
    //waiting for idle
    while(SST25Busy()){}
    //
    SST25Cs(0);
    Par.Val = addr;   
    SpiRw( SST25CMD_Read_Data);
    SpiRw( Par.byte.UB);
    SpiRw( Par.byte.HB);
    SpiRw( Par.byte.LB);
    while(Len--)
    {
        *Des++ = SpiRw( 0x55 );
    } 
    
    SST25Cs(1);
}

/*****************************************************************************//*!
* @brief   write data ,must be in same page.
*               
* @param   addr          address in chip
*          len           length will be read
*          des           source
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/ 
void SST25Write(uint32_t addr,uint32_t Len,uint8_t *Src)
{
    UINT32_VAL Par;
    
    //waiting for idle
    while(SST25Busy()){}

    Par.Val = addr;  
    while(Len--){
        SST25CmdWriteEn();
        NOP20();
        SST25Cs(0);
        SpiRw( SST25CMD_Byte_Program);
        SpiRw( Par.byte.UB);
        SpiRw( Par.byte.HB);
        SpiRw( Par.byte.LB);
        SpiRw( *Src++); 
        SST25Cs(1);
        Par.Val++;
        while(SST25Busy()){}
    }
    
    NOP20();
    while(SST25Busy()){}
    

}

/*****************************************************************************//*!
* @brief   read data.
*               
* @param   addr          address in chip
*          len           length will be read
*          des           destination
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/ 
void SST25DmaRead(uint32_t addr,uint32_t Len,uint8_t *Des)
{
    UINT32_VAL Par;
    
    //waiting for idle
    while(SST25Busy()){}
    //
    SST25Cs(0);
    Par.Val = addr;   
    SpiRw( SST25CMD_Read_Data);
    SpiRw( Par.byte.UB);
    SpiRw( Par.byte.HB);
    SpiRw( Par.byte.LB);

    SpiDmaRw(SST25Q_READ,  Len, Des);
    SST25Cs(1);
}

/*****************************************************************************//*!
* @brief   write data ,must be in same page.
*               
* @param   addr          address in chip
*          len           length will be read
*          des           source
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/ 
void SST25DmaWrite(uint32_t addr,uint32_t Len,uint8_t *Src)
{
    UINT32_VAL Par;
    
    //waiting for idle
    while(SST25Busy()){}
    while( SST25Q_ST_WRITE_EN != (SST25CmdStRead()&SST25Q_ST_WRITE_EN))
    SST25CmdWriteEn();
        
    SST25Cs(0);
    Par.Val = addr;   
    SpiRw( SST25CMD_AddrInc_Program);
    SpiRw( Par.byte.UB);
    SpiRw( Par.byte.HB);
    SpiRw( Par.byte.LB);
	
    SpiDmaRw(SST25Q_WRITE,  Len, Src);
    
    SST25Cs(1);
}
